using DBLibrary.HLBJMemoryTool;
using DevExpress.Xpo;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Server.DTOs;
using System;
using System.Linq;
using System.Threading.Tasks;
using FluentFTP;
using System.Net.Sockets;

namespace Server.Services
{
    /// <summary>
    /// FTP服务实现类，用于处理FTP相关操作
    /// </summary>
    public class FtpService : IFtpService
    {
        private readonly HLBJMemoryToolUnitOfWork _unitOfWork;
        private readonly ILogger<FtpService> _logger;
        private readonly string _ftpServerUrl;
        private readonly string _localFtpPath;
        private readonly string _ftpUsername;
        private readonly string _ftpPassword;

        public FtpService(HLBJMemoryToolUnitOfWork unitOfWork, ILogger<FtpService> logger, IConfiguration configuration)
        {
            _unitOfWork = unitOfWork;
            _logger = logger;

            // 从配置文件中读取FTP设置
            _ftpServerUrl = configuration.GetValue<string>("FtpSettings:FtpServerUrl") ?? "ftp://localhost";
            _localFtpPath = configuration.GetValue<string>("FtpSettings:LocalFtpPath") ?? "ftp://localhost";
            _ftpUsername = configuration.GetValue<string>("FtpSettings:FtpUsername") ?? "anonymous";
            _ftpPassword = configuration.GetValue<string>("FtpSettings:FtpPassword") ?? "";
        }

        /// <summary>
        /// 删除FTP服务器上的文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>是否删除成功</returns>
        public async Task<bool> DeleteFileFromFtpAsync(string filePath)
        {
            try
            {
                if (string.IsNullOrEmpty(filePath))
                {
                    _logger.LogWarning("要删除的文件路径为空");
                    return false;
                }

                // 确保filePath不包含开头的斜杠，以避免URL拼接错误
                filePath = filePath.TrimStart('/');

                // 构建完整的FTP文件URL，使用_localFtpPath作为基础路径
                string ftpFileUrl = $"{_localFtpPath.TrimEnd('/')}/{filePath}";
                _logger.LogInformation("准备删除FTP文件: {ftpFileUrl}", ftpFileUrl);

                // 使用 FluentFTP 的同步 API（包装到后台线程）以兼容当前库版本
                return await Task.Run(() => TryDeleteWithFluentSync(ftpFileUrl));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除FTP文件时发生错误");
                return false;
            }
        }

        // 使用 FluentFTP 同步 API 实现删除，增强连接重试/模式切换和日志
        private bool TryDeleteWithFluentSync(string ftpFileUrl)
        {
            var uri = new Uri(ftpFileUrl);
            var host = uri.Host;
            var port = uri.IsDefaultPort ? 21 : uri.Port;
            var path = Uri.UnescapeDataString(uri.AbsolutePath).TrimStart('/');
            var dir = PathGetDirectory(path);

            // 快速检查控制端口可达性，5s 超时
            if (!IsTcpPortOpen(host, port, 5000))
            {
                _logger.LogError("无法连接到 FTP 控制端口 {host}:{port}（TCP 连接失败或超时）", host, port);
                return false;
            }

            var modesToTry = new[] { FtpDataConnectionType.AutoPassive, FtpDataConnectionType.AutoActive };

            foreach (var mode in modesToTry)
            {
                var client = new FtpClient();
                client.Host = host;
                client.Port = port;
                client.Credentials = new System.Net.NetworkCredential(_ftpUsername, _ftpPassword);
                client.Config.RetryAttempts = 2;
                client.Config.ConnectTimeout = 30000; // 30s
                client.Config.ReadTimeout = 30000;
                client.Config.DataConnectionType = mode;

                _logger.LogInformation("尝试连接 FTP {host}:{port}，模式={mode}，超时={timeout}ms", host, port, mode, client.Config.ConnectTimeout);

                try
                {
                    client.Connect();
                    _logger.LogInformation("连接成功 (模式={mode})", mode);

                    // 检查目录 existence (optional)
                    try
                    {
                        if (!client.DirectoryExists(dir))
                        {
                            _logger.LogWarning("FluentFTP: 目标目录不存在: {dir}", dir);
                        }
                    }
                    catch (Exception exDir)
                    {
                        _logger.LogDebug(exDir, "检查目录存在性时出错 (忽略): {dir}", dir);
                    }

                    // 检查并删除文件
                    try
                    {
                        if (client.FileExists(path))
                        {
                            client.DeleteFile(path);
                            _logger.LogInformation("FluentFTP: 删除成功 {0}", ftpFileUrl);
                            return true;
                        }

                        _logger.LogWarning("FluentFTP: 文件不存在 {0}", ftpFileUrl);
                        return false;
                    }
                    catch (Exception exDel)
                    {
                        _logger.LogError(exDel, "FluentFTP: 删除文件时出现异常 (模式={mode}): {url}", mode, ftpFileUrl);
                        // 如果删除阶段出错，不立即放弃，先断开并尝试下一个模式
                    }
                    finally
                    {
                        try { client.Disconnect(); } catch { }
                        try { client.Dispose(); } catch { }
                    }
                }
                catch (Exception exConn)
                {
                    _logger.LogWarning(exConn, "FluentFTP: 连接失败 (模式={mode}) 到 {host}:{port}: {msg}", mode, host, port, exConn.Message);
                    try { client.Dispose(); } catch { }
                    // 尝试下一个模式
                }
            }

            _logger.LogError("FluentFTP 删除文件失败：所有连接模式尝试完毕，无法连接或删除: {url}", ftpFileUrl);
            return false;
        }

        private bool IsTcpPortOpen(string host, int port, int timeoutMs)
        {
            try
            {
                using var tcp = new TcpClient();
                var ar = tcp.BeginConnect(host, port, null, null);
                var success = ar.AsyncWaitHandle.WaitOne(timeoutMs);
                if (!success) return false;
                tcp.EndConnect(ar);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogDebug(ex, "TCP 端口检测失败: {host}:{port}", host, port);
                return false;
            }
        }

        private string PathGetDirectory(string path)
        {
            if (string.IsNullOrEmpty(path)) return string.Empty;
            var idx = path.LastIndexOf('/');
            if (idx <= 0) return "/";
            return path.Substring(0, idx);
        }

        /// <summary>
        /// 验证用户下载权限并返回FTP凭证
        /// 根据用户需求，只要数据库中有这个用户，就可以下载
        /// </summary>
        /// <param name="fileInfo">文件信息</param>
        /// <returns>FTP下载凭证，如果用户不存在则返回null</returns>
        public Task<Server.DTOs.FtpUploadCredentials?> VerifyDownloadPermissionAsync(Server.DTOs.FileInfo fileInfo)
        {
            try
            {
                if (fileInfo == null)
                {
                    _logger.LogWarning("文件信息为空");
                    return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(null);
                }

                // 处理客户端和服务器端FileInfo类结构不匹配的问题
                // 先尝试使用FileOwnerId（来自客户端的字符串用户ID）
                string userId = string.Empty;

                // 由于客户端的FileOwnerId是字符串，而服务器端定义为long，可能存在转换问题
                // 检查FileOwnerId是否为0，如果是，则检查UserId字段
                if (fileInfo.FileOwnerId == 0 && !string.IsNullOrEmpty(fileInfo.UserId))
                {
                    userId = fileInfo.UserId;
                    _logger.LogInformation("使用UserId字段进行下载权限验证: UserId = {UserId}", userId);
                }
                else
                {
                    // 使用FileOwnerId作为用户标识
                    userId = fileInfo.FileOwnerId.ToString();
                    _logger.LogInformation("验证用户下载权限: FileOwnerId = {UserId}", userId);
                }

                // 检查用户是否存在于UserInfo表中
                var userExists = new XPQuery<DBLibrary.HLBJMemoryTool.UserInfo>(_unitOfWork)
                    .Any(u => u.Id.ToString() == userId);

                if (userExists)
                {
                    _logger.LogInformation("用户验证成功，准备返回FTP凭证: {UserId}", userId);
                    // 返回FTP凭证（使用从配置文件中读取的凭证）
                    return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(new Server.DTOs.FtpUploadCredentials
                    {
                        FtpServerUrl = _ftpServerUrl, // 从配置文件读取的FTP服务器地址
                        FtpUsername = _ftpUsername, // 从配置文件读取的FTP用户名
                        FtpPassword = _ftpPassword, // 从配置文件读取的FTP密码
                        FtpDirectoryPath = userId // 为每个用户创建单独的目录
                    });
                }
                else
                {
                    _logger.LogWarning("用户不存在，拒绝下载权限: {UserId}", userId);
                    return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(null);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "验证下载权限时发生错误");
                return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(null);
            }
        }

        /// <summary>
        /// 验证用户上传权限并返回FTP凭证
        /// 根据用户需求，只要数据库中有这个用户，就可以上传
        /// </summary>
        /// <param name="uploadInfo">上传信息</param>
        /// <returns>FTP上传凭证，如果用户不存在则返回null</returns>
        public Task<Server.DTOs.FtpUploadCredentials?> VerifyUploadPermissionAsync(Server.DTOs.UploadInfo uploadInfo)
        {
            try
            {
                if (uploadInfo == null)
                {
                    _logger.LogWarning("上传信息为空");
                    return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(null);
                }

                // 检查用户是否存在于UserInfo表中
                _logger.LogInformation("验证用户上传权限: UserId = {UserId}", uploadInfo.UserId);
                var userExists = new XPQuery<DBLibrary.HLBJMemoryTool.UserInfo>(_unitOfWork)
                    .Any(u => u.Id.ToString() == uploadInfo.UserId);

                if (userExists)
                {
                    _logger.LogInformation("用户验证成功，准备返回FTP凭证: {UserId}", uploadInfo.UserId);
                    // 返回FTP凭证（使用从配置文件中读取的凭证）
                    return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(new Server.DTOs.FtpUploadCredentials
                    {
                        FtpServerUrl = _ftpServerUrl, // 从配置文件读取的FTP服务器地址
                        FtpUsername = _ftpUsername, // 从配置文件读取的FTP用户名
                        FtpPassword = _ftpPassword, // 从配置文件读取的FTP密码
                        FtpDirectoryPath = uploadInfo.UserId // 为每个用户创建单独的目录
                    });
                }
                else
                {
                    _logger.LogWarning("用户不存在，拒绝上传权限: {UserId}", uploadInfo.UserId);
                    return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(null);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "验证上传权限时发生错误");
                return Task.FromResult<Server.DTOs.FtpUploadCredentials?>(null);
            }
        }
    }
}